home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
HPAVC
/
HPAVC CD-ROM.iso
/
WANDR401.ZIP
/
sources
/
game.c
< prev
next >
Wrap
C/C++ Source or Header
|
1997-09-13
|
19KB
|
664 lines
/* game.c */
/* Adapted for the DJGPP ALLEGRO game package */
/* Seymour Shlien 24-Aug-97 */
/* This file contains the code for moving */
/* the explorer on the board and interating */
/* with the falling blocks, monsters, ... */
/* Besides the elimination of all the calls to curses/termcap */
/* and replacement with new functions in the display.c file, */
/* there were a few other changes made to the user interface. */
/* The #,~,?,q,m,n,<,> commands in the older version have been */
/* replaced with Function key commands and the F6 menu. Though */
/* R, S and cntl-R and cntl-W are still there, they are not */
/* supported commands. Hopefully, the player does not press */
/* these keys accidentally. cntl-L for loading the solution */
/* from a designated file if it exists is a new command */
/* described in the help.txt file. I didn't put it in the menu */
/* because I don't want everybody to know about it. */
/* Another significant change, is that the game either runs */
/* in record mode or playback. I got rid of all the checkpoint */
/* stuff +,-,& in the record/playback mode. Everything is now */
/* automatic and transparent to the user who does not have to */
/* remember to turn the recorder on or off as in wandr330.zip */
#include "wand_head.h"
#include <allegro.h>
#include "samples.h"
/* I do not install_keyboard() but use the regular bios keyboard */
/* driver. Except for cntl keys, users do not press two keys at once.*/
/* This makes debugging using Rhide1.3 a little easier. */
#define UP_ARROW 328
#define DOWN_ARROW 336
#define LEFT_ARROW 331
#define RIGHT_ARROW 333
int playback_flag; /* indicates whether F5 key is active */
extern int audio_flag; /* switches audio on or off */
extern int midi_flag; /* switches midi on or off */
extern int move_monsters();
extern int check();
extern void display();
extern int fall();
extern void map();
extern void redraw_screen();
extern struct mon_rec *make_monster();
/* This array contains the representation of the game/puzzle.
It is read in from one of the level files and the array
maintains the state of the game.
*/
extern char lscreen[NOOFROWS][ROWLEN+1];
extern int debug_disp; /* switches between map and zoom mode */
extern char *edit_memory; /* memory for all key strokes, the amount */
extern char *memory_end; /* of space is set by EMSIZE in wand_hea.h */
extern int pause2; /* for slowing playback and animation */
extern int pause1;
extern int gamelevel; /* The new level the user wants to go to */
extern int recording; /* Flag 1,2 for record and playback */
extern int signal_reload; /* from display.c indicates that level */
/* reload is necessary. */
struct mon_rec start_of_list = {0,0,0,0,0,NULL,NULL};
struct mon_rec *last_of_list, *tail_of_list;
int nx,ny; /* we need it global to allow for scrolling */
/* Actual game function - Calls fall() to move boulders and arrows
recursively.
Variable explanation :
x,y : where you are
nx,ny : where you're trying to move to
sx,sy : where the screen window on the playing area is
mx,my : where the monster is
tx,ty : teleport arrival
bx,by : baby monster position
nbx,nby : where it wants to be
lx,ly : the place you left when teleporting
nf : how many diamonds you've got so far
new_disp : the vector the baby monster is trying
*/
extern int old_score; /* save old score in case of retry or killed */
char *playscreen(num, score, maxmoves, keys)
int *num, maxmoves;
long *score;
char keys[10];
{
int x, y, deadyet = 0, sx = -1, sy = -1, tx = -1, ty = -1,
lx = 0, ly = 0, mx = -1, my = -1,
diamonds = 0, nf = 0, tmpx, tmpy;
char (*frow)[ROWLEN+1] = lscreen, buffer[25];
int ch;
struct mon_rec *monster;
static char howdead[25];
char *memory_ptr;
int ier;
int pathsize;
int signal_teleport; /* indicates teleport occurred (for zoom mode) */
char comment[60];
old_score = *score;
tail_of_list = &start_of_list;
memory_ptr = edit_memory;
/* Scan the screen and find the explorer, monsters and count the*/
/* number of diamonds. Replace teleport arrival with blank. */
for (x = 0; x <= ROWLEN; x++)
for (y = 0; y < NOOFROWS; y++) {
if ((lscreen[y][x] == '*') || (lscreen[y][x] == '+'))
diamonds++;
if (lscreen[y][x] == 'A') { /* note teleport arrival point & */
/* replace with space */
tx = x;
ty = y;
lscreen[y][x] = ' ';
}
if (lscreen[y][x] == '@') {
sx = x;
sy = y;
}
if (lscreen[y][x] == 'M') { /* Put megamonster in */
mx = x;
my = y;
}
if (lscreen[y][x] == 'S') { /* link small monster to pointer chain */
if ((monster = make_monster(x,y)) == NULL) {
strcpy(howdead,"running out of memory");
return howdead;
}
if (!viable(x,y-1)) { /* make sure its running in the */
/* correct direction.. */
monster->mx = 1;
monster->my = 0;
} else if (!viable(x+1,y)) {
monster->mx = 0;
monster->my = 1;
} else if (!viable(x,y+1)) {
monster->mx = -1;
monster->my = 0;
} else if (!viable(x-1,y)) {
monster->mx = 0;
monster->my = -1;
}
}
if (lscreen[y][x] == '-')
lscreen[y][x] = ' ';
}
x = sx;
y = sy;
if ((x == -1) && (y == -1)) { /* no start position in screen ? */
strcpy(howdead,"a screen design error");
return(howdead);
}
if (maxmoves < 1) maxmoves = -1;
update_game: /* restored game restarts here */
redraw_screen(maxmoves,*num,*score,nf,diamonds,mx,sx,sy,frow);
nx = x;
ny = y;
signal_teleport =0;
/* THE GAME STARTS HERE. */
while (deadyet == 0) {
refresh_screen();
switch (recording) {
case 1: /* Recording */
ch = getkey();
while (kbhit()) getch(); /* clear keyboard buffer */
/* convert arrow keys to movement keys if necessary*/
if (ch == LEFT_ARROW) ch = keys[2];
else if (ch == RIGHT_ARROW) ch = keys[3];
else if (ch == UP_ARROW) ch= keys[0];
else if (ch == DOWN_ARROW) ch = keys[1];
if((ch == keys[0]) || (ch == keys[1]) || (ch == keys[2]) ||
(ch == keys[3]))
{ *memory_ptr++ = ch;
maxmoves--;
memory_end++;
if(playback_flag == 1)
{
playback_flag =0;
make_control_bar();
}
}
else if(ch>31 && ch<128 && ch != 'R' && ch != 'S')
{ /* if not control or function key */
*memory_ptr++ = ' '; /* non movement keys represented */
memory_end++; /* by space. monsters can move*/
if(playback_flag == 1)
{
playback_flag =0;
make_control_bar();
}
}
if(maxmoves > 0) notify_maxmoves(maxmoves);
break;
case 2: /* Playback */
if (bioskey(1)) /* check for interrupt */
{ /* and stop playback if*/
recording = 1; /* present. */
continue;
}
ch = *memory_ptr;
memory_ptr++;
delay(pause2); /* slow it down */
if(ch != ' ') maxmoves--;
if (ch == '\0')
ch = ')';
break;
default:
alert_message("program error: recording not 1 or 2");
}
nx = x;
ny = y;
/************************************************************/
/* Execute movement keys */
/************************************************************/
if ((ch == keys[3]) && (x <(ROWLEN-1)))
nx++;
if ((ch == keys[2]) && (x > 0))
nx--;
if ((ch == keys[1]) && (y <(NOOFROWS-1)))
ny++;
if ((ch == keys[0]) && (y > 0))
ny--;
if (ch == 315) { /* F1. Help key */
show_help();
continue; /* don't move monsters */
}
if (ch == 316) { /* F2. About window */
draw_about_window();
continue; /* don't move monsters */
}
/**************************************************************/
/* Quit, Restart */
/**************************************************************/
if (ch == 318) { /* F4. restart same level */
if(memory_ptr != edit_memory) /* in case you press F4 twice */
{
playback_flag = 1;
*memory_ptr = ')';
}
*score = old_score;
sprintf(howdead,"~%c",*num);
return howdead;
}
if (ch == 27) { /* ESC. */
strcpy(howdead,"quitting the game");
return howdead;
}
/**************************************************************/
/* Display Options */
/**************************************************************/
if (ch == 317) { /* F3 */
debug_disp = 1 - debug_disp;
if(debug_disp) clear_remnant();
continue;
}
/**************************************************************/
/* Memory Functions */
/**************************************************************/
if (ch == ')')
{
if (recording == 2)
{
recording = 1;
memory_ptr--;
memory_end = memory_ptr;
}
continue; /* don't move monsters if present */
}
if (ch == 319) /* F5 */
{
if (playback_flag)
{ /* playback memory */
recording = 2;
playback_flag =0;
make_control_bar();
}
continue;
}
if (ch == 320) /* F6 */
{
menu_interface();
if(signal_reload)
{
sprintf(howdead,"~%c",gamelevel);
if(midi_flag) load_and_play_midi();
return howdead;
}
continue;
}
/**************************************************************/
/* Save, Restore options */
/**************************************************************/
/* Added save/restore game feature. Gregory H. Margo */
if (ch == 'S') { /* save game */
extern struct save_vars zz;
/* stuff away important local variables to be saved */
/* so the game state may be acurately restored */
zz.z_x = x;
zz.z_y = y;
zz.z_sx = sx;
zz.z_sy = sy;
zz.z_tx = tx;
zz.z_ty = ty;
zz.z_mx = mx;
zz.z_my = my;
zz.z_diamonds = diamonds;
zz.z_nf = nf;
save_game(*num, score, audio_flag, maxmoves);
/* NOTREACHED ... unless there's been an error. */
}
if (ch == 'R') { /* restore game */
extern struct save_vars zz;
ier = restore_game(num, score, audio_flag, &maxmoves);
if(ier == 0)
{
/* recover important local variables */
x = zz.z_x;
y = zz.z_y;
sx = zz.z_sx;
sy = zz.z_sy;
tx = zz.z_tx;
ty = zz.z_ty;
mx = zz.z_mx;
my = zz.z_my;
diamonds = zz.z_diamonds;
nf = zz.z_nf;
}
goto update_game; /* the dreaded goto */
}
if (ch == 12) /* ctrl l -- read solution data */
{
if(memory_ptr != edit_memory)
{
alert_message("First press F4 to restart");
continue;
}
ier = edit_restore(*num);
if(ier >= 0) playback_flag=1;
make_control_bar();
continue; /* do not move monsters if present */
}
if (ch == 18) /* ctrl r -- read memory data */
{ier = edit_restore(0);
if(ier >= 0) playback_flag=1;
make_control_bar();
continue; /* do not move monsters if present */
}
if (ch == 23) /* ctrl w -- write memory data */
{edit_save(-1);
continue;
}
if (lscreen[ny][nx] == 'C') {
lscreen[ny][nx] = ':';
*score+=4;
if(audio_flag) play_audio_sample(GET_CAPSULE_SND);
if (maxmoves != -1)
maxmoves+=250;
}
/**************************************************************/
/* G A M E A C T I O N S */
/**************************************************************/
switch (lscreen[ny][nx]) {
case '@': break;
case '*': *score+=9;
nf++;
notify_diamonds(nf,diamonds);
if(audio_flag) play_audio_sample(GET_DIAMOND_SND);
case ':': *score+=1;
notify_score(*score);
case ' ':
lscreen[y][x] = ' ';
lscreen[ny][nx] = '@';
draw_object(y,x,' ');
draw_object(ny,nx,'@');
deadyet += check(&mx,&my,x,y,nx-x,ny-y,sx,sy,howdead);
y = ny;
x = nx;
break;
case 'O':
if ((nx == 0) || (nx == ROWLEN)) break;
if (lscreen[y][nx*2-x] == 'M') {
lscreen[y][nx*2-x] = ' ';
mx = my = -1;
*score+=100;
notify_score(*score);
}
if (lscreen[y][nx*2-x] == ' ') {
lscreen[y][nx*2-x] = 'O';
lscreen[y][x] = ' ';
lscreen[ny][nx] = '@';
draw_object(y,x,' ');
draw_object(ny,nx,'@');
draw_object(y,nx*2-x,'O');
deadyet += fall(&mx,&my,nx*2-x,y+1,sx,sy,howdead);
deadyet += fall(&mx,&my,x*2-nx,y,sx,sy,howdead);
deadyet += fall(&mx,&my,x,y,sx,sy,howdead);
deadyet += fall(&mx,&my,x,y-1,sx,sy,howdead);
deadyet += fall(&mx,&my,x,y+1,sx,sy,howdead);
y = ny;
x = nx;
}
break;
case '^':
if ((nx == 0) || (nx == ROWLEN)) break;
if (lscreen[y][nx*2-x] == ' ') {
lscreen[y][nx*2-x] = '^';
lscreen[y][x] = ' ';
lscreen[ny][nx] = '@';
draw_object(y,x,' ');
draw_object(ny,nx,'@');
draw_object(y,nx*2-x,'^');
deadyet += fall(&mx,&my,nx*2-x,y-1,sx,sy,howdead);
deadyet += fall(&mx,&my,x*2-nx,y,sx,sy,howdead);
deadyet += fall(&mx,&my,x,y,sx,sy,howdead);
deadyet += fall(&mx,&my,x,y+1,sx,sy,howdead);
deadyet += fall(&mx,&my,x,y-1,sx,sy,howdead);
y = ny;
x = nx;
}
break;
case '<':
case '>':
if ((ny == 0) || (ny == NOOFROWS)) break;
if (lscreen[ny*2-y][x] == 'M') {
lscreen[ny*2-y][x] = ' ';
mx = my = -1;
*score+=100;
notify_score(*score);
}
if (lscreen[ny*2-y][x] == ' ') {
lscreen[ny*2-y][x] = lscreen[ny][nx];
lscreen[y][x] = ' ';
lscreen[ny][nx] = '@';
draw_object(y,x,' ');
draw_object(ny,nx,'@');
draw_object(ny*2-y,x,lscreen[ny*2-y][x]);
deadyet += fall(&mx,&my,x,y,sx,sy,howdead);
deadyet += fall(&mx,&my,x-1,(ny>y)?y:(y-1)
,sx,sy,howdead);
deadyet += fall(&mx,&my,x+1,(ny>y)?y:(y-1)
,sx,sy,howdead);
deadyet += fall(&mx,&my,x-1,ny*2-y,sx,sy,howdead);
deadyet += fall(&mx,&my,x+1,ny*2-y,sx,sy,howdead);
y = ny;
x = nx;
}
break;
case '~':
if (((2*nx-x) < 0) || ((ny*2-y) > NOOFROWS) || ((ny*2-y) < 0) ||
((2*nx-x) > ROWLEN)) break;
if (lscreen[ny*2-y][nx*2 -x] == 'M') {
lscreen[ny*2-y][nx*2-x] = ' ';
mx = my = -1;
*score+=100;
notify_score(*score);
}
if (lscreen[ny*2-y][nx*2-x] == ' ') {
lscreen[ny*2-y][nx*2-x] = '~';
lscreen[y][x] = ' ';
lscreen[ny][nx] = '@';
draw_object(y,x,' ');
draw_object(ny,nx,'@');
draw_object(ny*2-y,nx*2-x,'~');
deadyet += check(&mx,&my,x,y,nx-x,ny-y,sx,sy,howdead);
y = ny; x = nx;
}
break;
case '!':
strcpy(howdead,"an exploding landmine");
deadyet = 1;
draw_object(y,x,' ');
draw_object(ny,nx,'@');
if(audio_flag) play_audio_sample(KILLED_BY_MINE_SND);
break;
case 'X':
if (nf == diamonds) {
*score+=250;
recording=1;
playback_flag=0;
pathsize = size_of_path_file(*num);
if(recording == 1)
{
memory_ptr -= 2;
*memory_ptr = ')';
if(audio_flag) play_audio_sample(LEVEL_DONE_SND);
if(pathsize == 0)
{
edit_save(*num);
alert_congratulations(0);
}
else if ((pathsize - 5) > (memory_ptr - edit_memory))
{
edit_save(*num);
alert_congratulations(1);
}
}
gamelevel = (*num) + 1;
if(midi_flag) load_and_play_midi();
return NULL;
}
break;
case 'T':
if (tx > -1) {
lscreen[ny][nx] = ' ';
lscreen[y][x] = ' ';
lx = x;
ly = y;
y = ty;
x = tx;
lscreen[y][x] = '@';
sx = x;
sy = y;
*score += 20;
notify_score(*score);
map(frow);
signal_teleport =1;
deadyet += fall(&mx,&my,nx,ny,sx,sy,howdead);
if (deadyet == 0)
deadyet = fall(&mx,&my,lx,ly,sx,sy,howdead);
if (deadyet == 0)
deadyet = fall(&mx,&my,lx+1,ly-1,sx,sy,howdead);
if (deadyet == 0)
deadyet = fall(&mx,&my,lx+1,ly+1,sx,sy,howdead);
if (deadyet == 0)
deadyet = fall(&mx,&my,lx-1,ly+1,sx,sy,howdead);
if (deadyet == 0)
deadyet = fall(&mx,&my,lx-1,ly-1,sx,sy,howdead);
} else {
lscreen[ny][nx] = ' ';
printf("Teleport out of order");
}
break;
case 'M':
strcpy(howdead,"a hungry monster");
deadyet = 1;
draw_object(y,x,' ');
if(audio_flag) play_audio_sample(KILLED_BY_M_SND);
break;
case 'S':
strcpy(howdead,"walking into a monster");
deadyet = 1;
draw_object(y,x,' ');
if(audio_flag) play_audio_sample(KILLED_BY_S_SND);
break;
default:
break;
}
if ((y == ny) && (x == nx) && (maxmoves > 0))
notify_maxmoves(maxmoves);
if (maxmoves == 0) {
strcpy(howdead,"running out of moves");
if(audio_flag) play_audio_sample(NO_MOVES_SND);
deadyet = 1;
}
if (signal_teleport)
{
/* we have to update nx,ny here so the zoom screen */
/* scrolls the right location. */
nx = x;
ny = y;
draw_object(ny,nx,'@'); /* initiates the scrolling */
if(audio_flag) play_audio_sample(TELEPORT_SND);
signal_teleport = 0;
}
deadyet += move_monsters(&mx,&my,score,howdead,sx,sy
,nf,x,y,diamonds);
}
if(recording==1)
*(memory_ptr-2) = ')'; /* step back to avoid death */
playback_flag=1;
return(howdead);
}